/****************************************************************************
**
**	File Name   : MD5.h
**
**	Project     : DatChecker
**
**	Last Updated: $Header: /DatChecker.root/DatChecker/MD5.cpp 1     8/14/03 9:25a Neusel $
**
**	This code is "derived from the RSA Data Security, Inc. MD5 Message-
**	Digest Algorithm", and must include the following information:
+---------------------------------------------------------------------------+
|	Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.		|
|																			|
|	License to copy and use this software is granted provided that it is	|
|	identified as the "RSA Data Security, Inc. MD5 Message-Digest 			|
|	Algorithm" in all material mentioning or referencing this software or	|
|	this function.															|
|																			|
|	License is also granted to make and use derivative works provided that  |
|	such works are identified as "derived from the RSA Data Security, Inc.	|
|	MD5 Message-Digest Algorithm" in all material mentioning or referencing	|
|	the derived work.                                 						|
|																			|
|	RSA Data Security, Inc. makes no representations concerning either the  |
|	merchantability of this software or the suitability of this software	|
|	for any particular purpose.  It is provided "as is" without express or	|
|	implied warranty of any kind.											|
|																			|
|	These notices must be retained in any copies of any part of this		|
|	documentation and/or software.											|
+---------------------------------------------------------------------------+
**
****************************************************************************/
#include "stdafx.h"
#include "MD5.h"
/*	-----------------------------------------------------------------------
	Global Declarations
	-----------------------------------------------------------------------	*/
static const SIZE_T		kDigestStrLen = (MD5::kDigestLen * 2) + 
										(MD5::kDigestLen / 4) + 1;

static TCHAR			s_szDigest[kDigestStrLen];
/*	-----------------------------------------------------------------------
	Local Declarations
	-----------------------------------------------------------------------	*/
static BYTE 	cPadding[64] =	{
								0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
								0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
								};
/*
**	ROTATE_LEFT rotates x left n bits
*/
#define ROTATE_LEFT(x,n) _rotl((x),(n))
/*
**	F, G, H and I are basic MD5 functions.  FF, GG, HH, and II are 
**	transformations for rounds 1, 2, 3, and 4.  Rotation is separate from 
**	addition to prevent recomputation.
*/
#define F(x,y,z)		(((x) & (y)) | ((~x) & (z)))
#define FF(a, b, c, d, x, s, ac)	{ \
	(a) += F((b), (c), (d)) + (x) + DWORD(ac); \
	(a) = ROTATE_LEFT((a), (s)); \
	(a) += (b);	}

#define G(x,y,z)		(((x) & (z)) | ((y) & (~z)))
#define GG(a, b, c, d, x, s, ac)	{ \
	(a) += G((b), (c), (d)) + (x) + DWORD(ac); \
	(a) = ROTATE_LEFT((a), (s)); \
	(a) += (b);	}

#define H(x,y,z)		((x) ^ (y) ^ (z))
#define HH(a, b, c, d, x, s, ac)	{ \
	(a) += H((b), (c), (d)) + (x) + DWORD(ac); \
	(a) = ROTATE_LEFT((a), (s)); \
	(a) += (b);	}

#define I(x,y,z)		((y) ^ ((x) | (~z)))
#define II(a, b, c, d, x, s, ac)	{ \
	(a) += I((b), (c), (d)) + (x) + DWORD(ac); \
	(a) = ROTATE_LEFT((a), (s)); \
	(a) += (b);	}

/****************************************************************************
**
**	MD5::ConvertToASCII() --	
**
*/
LPCTSTR							// ptr to string representation
MD5::ConvertToASCII(
	const MD5::Digest	digest)	// digest
{
BYTE const *	pc = digest;

::ZeroMemory(s_szDigest, sizeof(s_szDigest));
for (int ndx = 0; ndx < kDigestLen; ++ndx)
	{
	int		nLen;
	char	szTmp[8];

	nLen = _snprintf(szTmp, 8, "%02x", int(*pc++));
	ATLASSERT(nLen < 8);

	strncat(s_szDigest, szTmp, kDigestStrLen);
	if (((ndx + 1) % 4) == 0)
		strncat(s_szDigest, _T(" "), kDigestStrLen);
	}

return s_szDigest;
}	/* end of ConvertToASCII() */
/****************************************************************************
**
**	MD5::Start() -- resets the MD5 digest to it's initial state.
**
*/
void
MD5::Start(void)
{
m_dwBits[0] = m_dwBits[1] = 0L;

//	Load magic initialization constants.
m_dwBuffer[0] = DWORD( 0x67452301L );
m_dwBuffer[1] = DWORD( 0xEFCDAB89L );
m_dwBuffer[2] = DWORD( 0x98BADCFEL );
m_dwBuffer[3] = DWORD( 0x10325476L );

::ZeroMemory(m_digest, sizeof(Digest));
}	/* end of MD5::Start() */
/****************************************************************************
**
**	MD5::Stop() -- terminates the message-digest computation and ends with 
**		the desired message digest in m_digest[0...15].
**
*/
void
MD5::Stop(void)
{
int		ndx1,
		ndx2;
DWORD	dwBits,
		dwPadding,
		dwScratch[16];

dwScratch[14] = m_dwBits[0];	// save number of bits
dwScratch[15] = m_dwBits[1];
dwBits = (m_dwBits[0] >> 3) & 0x3F;
dwPadding = ((dwBits < 56) ? 56 : 120) - dwBits;	// pad to 56 mod 64

Update(cPadding, dwPadding);
/*
**	Append length in bits and transform
*/
for (ndx1 = ndx2 = 0; ndx1 < 14; ndx1++, ndx2 += 4)
	{
	dwScratch[ndx1] =	(DWORD(m_cInput[ndx2 + 3]) << 24) |
						(DWORD(m_cInput[ndx2 + 2]) << 16) |
						(DWORD(m_cInput[ndx2 + 1]) << 8) |
						 DWORD(m_cInput[ndx2]);
	}

transform(dwScratch);
/*
**	Now copy the buffer to our digest
*/
for (ndx1 = ndx2 = 0; ndx1 < 4; ndx1++, ndx2 += 4)
	{
	m_digest[ndx2] =		BYTE(m_dwBuffer[ndx1] & 0xFF);
	m_digest[ndx2 + 1] =	BYTE((m_dwBuffer[ndx1] >> 8) & 0xFF);
	m_digest[ndx2 + 2] =	BYTE((m_dwBuffer[ndx1] >> 16) & 0xFF);
	m_digest[ndx2 + 3] =	BYTE((m_dwBuffer[ndx1] >> 24) & 0xFF);
	}
}	/* end of MD5::Stop() */
/****************************************************************************
**
**	MD5::Update() -- updates the message-digest context to account for the 
**		presence of each of the characters pc[0..dwBytes - 1] in the message 
**		whose digest is being computed.
**
*/
void
MD5::Update(
	BYTE const *	pc,			// ptr to data
	DWORD			dwBytes)	// size of data in bytes
{
if (NULL_PTR(pc) || dwBytes == 0)
	return;	// nothing to do if caller passed us garbage
/*
**	Compute number of bytes mod 64
*/
int	ndx1,
		ndx2,
		iBits;
DWORD	dwScratch[16];

iBits = int((m_dwBits[0] >> 3) & 0x3F);
if ((m_dwBits[0] + (dwBytes << 3)) < m_dwBits[0])
	m_dwBits[1]++;	//	update number of bits

m_dwBits[0] += dwBytes << 3;
m_dwBits[1] += dwBytes >> 29;
/*
**	Now traverse the data one byte at a time, adding it to the input buffer
**	and transforming it when necessary.
*/
while (dwBytes--)
	{
	m_cInput[iBits++] = *pc++;
	if (iBits >= 0x40)
		{
		for (ndx1 = ndx2 = 0; ndx1 < 16; ndx1++, ndx2 += 4)
			{
			dwScratch[ndx1] =	(DWORD(m_cInput[ndx2 + 3]) << 24) |
								(DWORD(m_cInput[ndx2 + 2]) << 16) |
								(DWORD(m_cInput[ndx2 + 1]) << 8)  |
								 DWORD(m_cInput[ndx2]);
			}

		transform(dwScratch);
		iBits = 0;
		}
	}
}	/* end of MD5::Update() */
/****************************************************************************
**
**	MD5::transform() -- transforms m_dwBuffer based on dwScratch.  Note that 
**		if the Mysterious Constants are arranged backwards in little-endian 
**		order and decrypted with the DES they produce OCCULT MESSAGES!
**
*/
void
MD5::transform(
	const DWORD	dwScratch[])		// array of scratch data to transform against
{
DWORD		a = m_dwBuffer[0],
			b = m_dwBuffer[1],
			c = m_dwBuffer[2],
			d = m_dwBuffer[3];
/*
**	Round #1
*/
#define S11		7
#define S12		12
#define S13		17
#define S14		22
  FF( a, b, c, d, dwScratch[ 0], S11, 0xD76AA478L);	/* 1 */
  FF( d, a, b, c, dwScratch[ 1], S12, 0xE8C7B756L);	/* 2 */
  FF( c, d, a, b, dwScratch[ 2], S13, 0x242070DBL);	/* 3 */
  FF( b, c, d, a, dwScratch[ 3], S14, 0xC1BDCEEEL);	/* 4 */
  FF( a, b, c, d, dwScratch[ 4], S11, 0xF57C0FAFL);	/* 5 */
  FF( d, a, b, c, dwScratch[ 5], S12, 0x4787C62AL);	/* 6 */
  FF( c, d, a, b, dwScratch[ 6], S13, 0xA8304613L);	/* 7 */
  FF( b, c, d, a, dwScratch[ 7], S14, 0xFD469501L);	/* 8 */
  FF( a, b, c, d, dwScratch[ 8], S11, 0x698098D8L);	/* 9 */
  FF( d, a, b, c, dwScratch[ 9], S12, 0x8B44F7AFL);	/* 10 */
  FF( c, d, a, b, dwScratch[10], S13, 0xFFFF5BB1L);	/* 11 */
  FF( b, c, d, a, dwScratch[11], S14, 0x895CD7BEL);	/* 12 */
  FF( a, b, c, d, dwScratch[12], S11, 0x6B901122L);	/* 13 */
  FF( d, a, b, c, dwScratch[13], S12, 0xFD987193L);	/* 14 */
  FF( c, d, a, b, dwScratch[14], S13, 0xA679438EL);	/* 15 */
  FF( b, c, d, a, dwScratch[15], S14, 0x49B40821L);	/* 16 */
/*
**	Round #2
*/
#define S21		5
#define S22		9
#define S23		14
#define S24		20
  GG( a, b, c, d, dwScratch[ 1], S21, 0xF61E2562L);	/* 17 */
  GG( d, a, b, c, dwScratch[ 6], S22, 0xC040B340L);	/* 18 */
  GG( c, d, a, b, dwScratch[11], S23, 0x265E5A51L);	/* 19 */
  GG( b, c, d, a, dwScratch[ 0], S24, 0xE9B6C7AAL);	/* 20 */
  GG( a, b, c, d, dwScratch[ 5], S21, 0xD62F105DL);	/* 21 */
  GG( d, a, b, c, dwScratch[10], S22, 0x02441453L);	/* 22 */
  GG( c, d, a, b, dwScratch[15], S23, 0xD8A1E681L);	/* 23 */
  GG( b, c, d, a, dwScratch[ 4], S24, 0xE7D3FBC8L);	/* 24 */
  GG( a, b, c, d, dwScratch[ 9], S21, 0x21E1CDE6L);	/* 25 */
  GG( d, a, b, c, dwScratch[14], S22, 0xC33707D6L);	/* 26 */
  GG( c, d, a, b, dwScratch[ 3], S23, 0xF4D50D87L);	/* 27 */
  GG( b, c, d, a, dwScratch[ 8], S24, 0x455A14EDL);	/* 28 */
  GG( a, b, c, d, dwScratch[13], S21, 0xA9E3E905L);	/* 29 */
  GG( d, a, b, c, dwScratch[ 2], S22, 0xFCEFA3F8L);	/* 30 */
  GG( c, d, a, b, dwScratch[ 7], S23, 0x676F02D9L);	/* 31 */
  GG( b, c, d, a, dwScratch[12], S24, 0x8D2A4C8AL);	/* 32 */
/*
**	Round #3
*/
#define S31		4
#define S32		11
#define S33		16
#define S34		23
  HH( a, b, c, d, dwScratch[ 5], S31, 0xFFFA3942L);	/* 33 */
  HH( d, a, b, c, dwScratch[ 8], S32, 0x8771F681L);	/* 34 */
  HH( c, d, a, b, dwScratch[11], S33, 0x6D9D6122L);	/* 35 */
  HH( b, c, d, a, dwScratch[14], S34, 0xFDE5380CL);	/* 36 */
  HH( a, b, c, d, dwScratch[ 1], S31, 0xA4BEEA44L);	/* 37 */
  HH( d, a, b, c, dwScratch[ 4], S32, 0x4BDECFA9L);	/* 38 */
  HH( c, d, a, b, dwScratch[ 7], S33, 0xF6BB4B60L);	/* 39 */
  HH( b, c, d, a, dwScratch[10], S34, 0xBEBFBC70L);	/* 40 */
  HH( a, b, c, d, dwScratch[13], S31, 0x289B7EC6L);	/* 41 */
  HH( d, a, b, c, dwScratch[ 0], S32, 0xEAA127FAL);	/* 42 */
  HH( c, d, a, b, dwScratch[ 3], S33, 0xD4EF3085L);	/* 43 */
  HH( b, c, d, a, dwScratch[ 6], S34, 0x04881D05L);	/* 44 */
  HH( a, b, c, d, dwScratch[ 9], S31, 0xD9D4D039L);	/* 45 */
  HH( d, a, b, c, dwScratch[12], S32, 0xE6DB99E5L);	/* 46 */
  HH( c, d, a, b, dwScratch[15], S33, 0x1FA27CF8L);	/* 47 */
  HH( b, c, d, a, dwScratch[ 2], S34, 0xC4AC5665L);	/* 48 */
/*
**	Round #4
*/
#define S41		6
#define S42		10
#define S43		15
#define S44		21
  II( a, b, c, d, dwScratch[ 0], S41, 0xF4292244L);	/* 49 */
  II( d, a, b, c, dwScratch[ 7], S42, 0x432AFF97L);	/* 50 */
  II( c, d, a, b, dwScratch[14], S43, 0xAB9423A7L);	/* 51 */
  II( b, c, d, a, dwScratch[ 5], S44, 0xFC93A039L);	/* 52 */
  II( a, b, c, d, dwScratch[12], S41, 0x655B59C3L);	/* 53 */
  II( d, a, b, c, dwScratch[ 3], S42, 0x8F0CCC92L);	/* 54 */
  II( c, d, a, b, dwScratch[10], S43, 0xFFEFF47DL);	/* 55 */
  II( b, c, d, a, dwScratch[ 1], S44, 0x85845DD1L);	/* 56 */
  II( a, b, c, d, dwScratch[ 8], S41, 0x6FA87E4FL);	/* 57 */
  II( d, a, b, c, dwScratch[15], S42, 0xFE2CE6E0L);	/* 58 */
  II( c, d, a, b, dwScratch[ 6], S43, 0xA3014314L);	/* 59 */
  II( b, c, d, a, dwScratch[13], S44, 0x4E0811A1L);	/* 60 */
  II( a, b, c, d, dwScratch[ 4], S41, 0xF7537E82L);	/* 61 */
  II( d, a, b, c, dwScratch[11], S42, 0xBD3AF235L);	/* 62 */
  II( c, d, a, b, dwScratch[ 2], S43, 0x2AD7D2BBL);	/* 63 */
  II( b, c, d, a, dwScratch[ 9], S44, 0xEB86D391L);	/* 64 */

m_dwBuffer[0] += a;
m_dwBuffer[1] += b;
m_dwBuffer[2] += c;
m_dwBuffer[3] += d;
}	/* end of MD5::transform() */
/****************************************************************************
**
**	End of MD5.cpp
**
****************************************************************************/
